package com.qianfeng.service.impl;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.qianfeng.Event.DeviceCommandEvent;
import com.qianfeng.cache.CategoryCache;
import com.qianfeng.exception.AddDataException;
import com.qianfeng.exception.FindDataException;
import com.qianfeng.mapper.DeviceMapper;
import com.qianfeng.pojo.*;
import com.qianfeng.service.DeviceService;
import com.qianfeng.service.SceneService;
import com.qianfeng.status.ResultCode;
import com.qianfeng.utils.LoginUsersUtils;
import com.qianfeng.valigroup.Insert;
import com.sun.org.apache.bcel.internal.generic.NEW;
import org.checkerframework.checker.units.qual.A;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;

import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CompletableFuture;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/*
 *@Description:
 *@author:刘哥
 *@Date:86180 2022/9/8 20:10
 */
@Service
//@Transactional
public class DeviceServiceImpl implements DeviceService {
    private ApplicationContext context;
    @Autowired
    public void setContext(ApplicationContext context) {
        this.context = context;
    }

    private ObjectMapper objectMapper;
    @Autowired
    public void setObjectMapper(ObjectMapper objectMapper) {
        this.objectMapper = objectMapper;
    }

    private SceneService sceneService;
    @Autowired
    public void setSceneService(SceneService sceneService) {
        this.sceneService = sceneService;
    }

    private CategoryCache categoryCache;
    @Autowired
    public void setCategoryCache(CategoryCache categoryCache) {
        this.categoryCache = categoryCache;
    }

    private DeviceMapper deviceMapper;

    @Autowired
    public void setDeviceMapper(DeviceMapper deviceMapper) {
        this.deviceMapper = deviceMapper;
    }

    @Override
    public List<SysDevice> findByCId(Long cId) {
        List<SysDevice> sysDevice=deviceMapper.findById(cId);
        return sysDevice;
    }

    @Override
    public void addDevice(SysDevice device) {
//        获取登录信息封装设备信息用
        BaseUser loginUser = LoginUsersUtils.getLoginUser();
        device.setBindUserId(loginUser.getUserId());
//        判断改商品的分类是否存在
        SysCategory category = categoryCache.get(device.getCategyId());
        Assert.notNull(category,()->{
            throw new AddDataException("分类不存在", ResultCode.DATA_NOT_EXIST);
        });
//        判断是否有传递场景id,有则判断场景id是否属于当前用户(没有则用默认值)
        Long sceneId = device.getSceneId();
        if (sceneId != null &&(sceneId<-1||sceneId==0)) {
            //传递了id不符合要求
            throw new AddDataException("场景不存在", ResultCode.DATA_NOT_EXIST);
        }else if (sceneId!=null&&sceneId>0){
//             传递了一个场景id,但是这个场景不一定属于谁
//             判断是否属于当前用户
            Scene byId = sceneService.findById(sceneId);
            Assert.isTrue(byId.getCreateBy().equals(loginUser.getUserId()),()->{
                throw new AddDataException("当前用户没有此场景",ResultCode.DATA_NOT_EXIST);
            });

        }

//        判断当前设备是否又被他人绑定(设备的id是出场自带的,不可更改)
        SysDevice deviceList = findById(device.getDeviceId());
        Assert.isTrue(deviceList==null||deviceList.getBindUserId().equals(device.getBindUserId()),()->{
            throw new AddDataException("该设备已经被绑定",ResultCode.DEVICE_ALREADY_BIND);
        });
        if (deviceList == null) {
//            进行设备添加绑定
            deviceMapper.bindDevice(device);
        }

    }

    private SysDevice findById(String deviceId) {
       return deviceMapper.findByDeviceId(deviceId);
    }

    @Override
    public SysDevice findByDeviceId(String deviceId) {
        BaseUser loginUser = LoginUsersUtils.getLoginUser();
        SysDevice byDeviceId = deviceMapper.findByDeviceId(deviceId);
        Assert.isTrue(byDeviceId!=null && byDeviceId.getBindUserId().equals(loginUser.getUserId()),()->{
            throw new FindDataException("此设备不存在",ResultCode.DATA_NOT_EXIST);
        });
        return byDeviceId;
    }

    @Override
    public void deleteByDeviceId(String deviceId) {
        SysDevice device = findByDeviceId(deviceId);
        deviceMapper.deleteByDeviceId(deviceId);
    }

    @Override
    public void updateDevice(SysDevice device) {
        BaseUser loginUser = LoginUsersUtils.getLoginUser();
        SysDevice bySceneId = deviceMapper.findByDeviceId(device.getDeviceId());
        Assert.isTrue(bySceneId!=null && bySceneId.getBindUserId().equals(loginUser.getUserId()), ()->{
            throw new FindDataException("此设备找不到",ResultCode.DATA_NOT_EXIST);
        });
//      判断当前传入的场景是不是当前用户的
        if(device.getSceneId()!=null && device.getSceneId()>0){
            Scene byId1 = sceneService.findById(device.getSceneId());
        }else if (device.getSceneId() != null &&(device.getSceneId()<-1||device.getSceneId()==0)) {
            //传入的场景id
            throw new AddDataException("场景不存在", ResultCode.DATA_NOT_EXIST);
        }

        if(bySceneId.getSceneId()!=null && bySceneId.getSceneId()>0){
            Scene byId = sceneService.findById(bySceneId.getSceneId());
        }else if (bySceneId.getSceneId() != null &&(bySceneId.getSceneId()<-1||bySceneId.getSceneId()==0)) {
            //当前设备绑定的场景
            throw new AddDataException("当前设备绑定的场景不存在", ResultCode.DATA_NOT_EXIST);
        }
        device.setBindUserId(loginUser.getUserId());
        deviceMapper.updateDevice(device);
    }

    @Override
    public List<SysDevice> findBySceneId(Long sceneId) {
        BaseUser loginUser = LoginUsersUtils.getLoginUser();
        List<SysDevice> device=deviceMapper.findBySceneId(sceneId);
        List<SysDevice> collect = device.stream()
                .filter(d -> {
                    return d.getBindUserId().equals(loginUser.getUserId());
                }).collect(Collectors.toList());
        return collect;
    }

    @Override
    public  List<SysDevice>  findAll() {
        BaseUser loginUser = LoginUsersUtils.getLoginUser();
        return deviceMapper.findAll(loginUser.getUserId());

    }

    @Override
    public void sendCommand(String deviceId, String command) {
        Assert.isTrue(StringUtils.hasText(deviceId) && StringUtils.hasText(command), () -> {
            throw new FindDataException("请输入设备id和指令",ResultCode.PARAM_CONTENT_EMPTY);
        });
//        需要根据设备id查询到对应的指令
        try {
            SysDevice byDeviceId = findByDeviceId(deviceId);
            Assert.notNull(byDeviceId,()->{
                throw new FindDataException("设备不存在",ResultCode.DATA_NOT_EXIST);
            });
            SysCategory category = categoryCache.get(byDeviceId.getCategyId());
            Assert.notNull(category,()->{
                throw new FindDataException("该设备分类不存在",ResultCode.DATA_NOT_EXIST);
            });
//        获取分类的操作指令
            String txCommand = category.getTxCommand();
//        将json格式的指令封装为集合
            Map map = objectMapper.readValue(txCommand,Map.class);
            //根据传递过来的命令key获取到对应的命令数据
            if (map.get(command) instanceof Map){
                Map cMap = (Map) map.get(command);
                if (cMap != null) {
                    Integer type = (Integer) cMap.get("type");
                    if (type != null) {
                        if (type == 1) {
                            context.publishEvent(new DeviceCommandEvent(deviceId, (String) cMap.get("command")));
                        }else if (type == 0){
                            context.publishEvent(new DeviceCommandEvent(deviceId,(String) cMap.get("command")));
                        }
                    }
                    //更新设备控制时间
                    updateControlTime(deviceId);
                    return;
                }
            }


//        command属性就是操作的指令

        } catch (JsonProcessingException e) {
            e.printStackTrace();
        }
    }

    private void updateControlTime(String deviceId) {
        CompletableFuture.runAsync(()->{
            SysDevice sysDevice = new SysDevice();
            sysDevice.setDeviceId(deviceId);
            sysDevice.setLastControlTime(new Date());
            deviceMapper.updateLastControlTime(sysDevice);

        });
    }

    @Override
    public int updateDeviceStatus(String deviceId, int status) {
        return deviceMapper.updateDeviceStatus(deviceId, status);
    }

}
